package com.hihuzi.lambda.util;

import com.hihuzi.lambda.annotation.LBiFunction;
import com.hihuzi.lambda.annotation.LFunction;
import com.hihuzi.lambda.entity.Person;
import com.hihuzi.lambda.entity.SerializedLambda;

import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class AnalysisUtil {
    /**
     * 获取类的对象方法-不带形参（序列化方式）
     *
     * @param function
     * @param <T>
     * @return
     */
    public static <T> SerializedLambda lffSimple(LFunction<T, ?> function) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
        try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
            oos.writeObject(function);
            oos.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        try (ObjectInputStream inputStream = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray())) {
            Class<?> clazz;

            @Override
            protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
                clazz = super.resolveClass(desc);
                return clazz == java.lang.invoke.SerializedLambda.class ? SerializedLambda.class : clazz;
            }
        }) {
            return (SerializedLambda) inputStream.readObject();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取类的对象方法-不带形参（反射方式）
     *
     * @param function
     * @param <T>
     * @return
     */
    public static <T> java.lang.invoke.SerializedLambda lfSimple(LFunction<T, ?> function) {
        Method method = function.getClass().getDeclaredMethods()[1];
        method.setAccessible(true);
        try {
            return (java.lang.invoke.SerializedLambda) method.invoke(function);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取类的对象方法-带形参（反射方式）
     *
     * @param function
     * @param <T>
     * @return
     */
    public static <T, U> java.lang.invoke.SerializedLambda lfSimple(LBiFunction<T, U, ?> function) {
        Method method = function.getClass().getDeclaredMethods()[1];
        method.setAccessible(true);
        try {
            return (java.lang.invoke.SerializedLambda) method.invoke(function);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取类的对象方法-带形参 通过反射+序列化替换对象
     *
     * @param function
     * @param <T>
     * @return
     */
    public static <T> SerializedLambda lfS(LFunction<T,?> function) {
        Method method = function.getClass().getDeclaredMethods()[1];
        method.setAccessible(true);
        try {
            Object invoke = method.invoke(function);
            ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
            try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
                oos.writeObject(invoke);
                oos.flush();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            try (ObjectInputStream inputStream = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray())) {
                Class<?> clazz;

                @Override
                protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
                    clazz = super.resolveClass(desc);
                    return clazz == java.lang.invoke.SerializedLambda.class ? SerializedLambda.class : clazz;
                }
            }) {
                return (SerializedLambda) inputStream.readObject();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        lfSimple(Person::setName);

    }
}
